package org.sample.springbootredis.service;

import org.redisson.api.RedissonClient;
import org.sample.springbootredis.client.DatabaseUserClient;
import org.sample.springbootredis.client.model.DateDTO;
import org.sample.springbootredis.client.model.UserDTO;
import org.sample.springbootredis.lock.LockKey;
import org.sample.springbootredis.lock.LockType;
import org.sample.springbootredis.lock.RedissonLock;
import org.sample.springbootredis.lock.RedissonLockConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class LockUserService {

	private static final Logger LOGGER = LoggerFactory.getLogger(LockUserService.class);

	@Autowired
	private DatabaseUserClient client;

	@Autowired
	private RedissonClient redisson;

	private RedissonLock createLock(LockType lockType, Long id) {
		RedissonLockConfig lockConfig = new RedissonLockConfig(redisson, lockType, LockKey.USER);
		lockConfig.addLockSubKey(Long.toString(id));
		lockConfig.setWaitMillis(10000);
		lockConfig.setLeaseMillis(50000);
		return RedissonLock.create(lockConfig);
	}

	public List<UserDTO> findAllUsers() {
		return client.findAll();
	}

	public UserDTO findUserById(Long id) {
		RedissonLock lock = createLock(LockType.READ_LOCK, id);
		if (lock.tryLock()) {
			try {
				Thread.sleep(10000);
			} catch (Exception e) {
				LOGGER.error("Thread is interrupted", e);
			} finally {
				lock.unlock();
			}
		}
		return client.findById(id);
	}

	public UserDTO findUserByName(String userName) {
		return client.findByUserName(userName);
	}

	public UserDTO createUser(UserDTO userDTO) {
		return client.create(userDTO);
	}

	public UserDTO updateUserById(UserDTO userDTO) {
		RedissonLock lock = createLock(LockType.WRITE_LOCK, userDTO.getId());
		if (lock.tryLock()) {
			try {
				Thread.sleep(10000);
			} catch (Exception e) {
				LOGGER.error("Thread is interrupted", e);
			} finally {
				lock.unlock();
			}
		}
		return client.updateById(userDTO.getId(), userDTO);
	}

	public UserDTO updateUserByName(UserDTO userDTO) {
		return client.updateByName(userDTO.getUserName(), userDTO);
	}

	public void deleteUserById(Long id) {
		RedissonLock lock = createLock(LockType.WRITE_LOCK, id);
		if (lock.tryLock()) {
			try {
				Thread.sleep(10000);
			} catch (Exception e) {
				LOGGER.error("Thread is interrupted", e);
			} finally {
				lock.unlock();
			}
		}
		client.deleteById(id);
	}

	public void deleteUserByName(String userName) {
		client.deleteByName(userName);
	}

	public List<UserDTO> findByCreatedDate(String createdDate) {
		DateDTO createdDateDTO = new DateDTO();
		createdDateDTO.setDate(createdDate);
		return client.findByCreatedDate(createdDateDTO);
	}

}
